Dump descriptors from a file#246
Conversation
ribalda
commented
Mar 12, 2026
|
oh, i've wanted this for a while, thanks! let me run some basic tests and then look closer at this next week. |
| cfg->MaxPower = buf[8]; | ||
|
|
||
| if (cfg->bNumInterfaces > 0) { | ||
| cfg->interface = calloc(cfg->bNumInterfaces, sizeof(*cfg->interface)); |
Check failure
Code scanning / CodeQL
Uncontrolled allocation size
There was a problem hiding this comment.
cfg->bNumInterfaces = buf[4];
The value of bNumInterfaces is capped to 255 because it comes from a single byte
| alt->bInterfaceProtocol = buf[7]; | ||
| alt->iInterface = buf[8]; | ||
| if (alt->bNumEndpoints > 0) { | ||
| alt->endpoint = calloc(alt->bNumEndpoints, sizeof(*alt->endpoint)); |
Check failure
Code scanning / CodeQL
Uncontrolled allocation size
There was a problem hiding this comment.
Same as before
alt->bNumEndpoints = buf[4];
| * | ||
| * Returns a pointer to the allocated configuration descriptor, or NULL on failure. | ||
| */ | ||
| static struct libusb_config_descriptor *parse_config_descriptor(const unsigned char *buf, int size) |
Check warning
Code scanning / CodeQL
Poorly documented large function
| switch (type) { | ||
| case LIBUSB_DT_INTERFACE: | ||
| if (buf[2] >= cfg->bNumInterfaces) | ||
| break; | ||
| ifc = (struct libusb_interface *)&cfg->interface[buf[2]]; | ||
| ifc->num_altsetting++; | ||
| tmp = realloc((void *)ifc->altsetting, ifc->num_altsetting * sizeof(*ifc->altsetting)); | ||
| if (!tmp) { | ||
| perror("realloc"); | ||
| desc_file_free_config_descriptor(cfg); | ||
| return NULL; | ||
| } | ||
| ifc->altsetting = tmp; | ||
| alt = (struct libusb_interface_descriptor *)&ifc->altsetting[ifc->num_altsetting - 1]; | ||
| memset(alt, 0, sizeof(*alt)); | ||
| alt->bLength = buf[0]; | ||
| alt->bDescriptorType = buf[1]; | ||
| alt->bInterfaceNumber = buf[2]; | ||
| alt->bAlternateSetting = buf[3]; | ||
| alt->bNumEndpoints = buf[4]; | ||
| alt->bInterfaceClass = buf[5]; | ||
| alt->bInterfaceSubClass = buf[6]; | ||
| alt->bInterfaceProtocol = buf[7]; | ||
| alt->iInterface = buf[8]; | ||
| if (alt->bNumEndpoints > 0) { | ||
| alt->endpoint = calloc(alt->bNumEndpoints, sizeof(*alt->endpoint)); | ||
| if (!alt->endpoint) { | ||
| perror("calloc"); | ||
| desc_file_free_config_descriptor(cfg); | ||
| return NULL; | ||
| } | ||
| } | ||
| ep = NULL; | ||
| break; | ||
|
|
||
| case LIBUSB_DT_ENDPOINT: | ||
| if (!(alt && alt->endpoint)) | ||
| break; | ||
| ep_idx = 0; | ||
| /* Find next free endpoint slot */ | ||
| while (ep_idx < alt->bNumEndpoints && alt->endpoint[ep_idx].bLength) | ||
| ep_idx++; | ||
| if (ep_idx < alt->bNumEndpoints) { | ||
| ep = (struct libusb_endpoint_descriptor *)&alt->endpoint[ep_idx]; | ||
| ep->bLength = buf[0]; | ||
| ep->bDescriptorType = buf[1]; | ||
| ep->bEndpointAddress = buf[2]; | ||
| ep->bmAttributes = buf[3]; | ||
| ep->wMaxPacketSize = buf[4] | (buf[5] << 8); | ||
| ep->bInterval = buf[6]; | ||
| ep->bRefresh = (len > 7) ? buf[7] : 0; | ||
| ep->bSynchAddress = (len > 8) ? buf[8] : 0; | ||
| } | ||
| break; | ||
|
|
||
| default: | ||
| /* Extra descriptors */ | ||
| if (ep) { | ||
| tmp = realloc((void *)ep->extra, ep->extra_length + len); | ||
| if (!tmp) { | ||
| perror("realloc"); | ||
| desc_file_free_config_descriptor(cfg); | ||
| return NULL; | ||
| } | ||
| ep->extra = tmp; | ||
| memcpy((void *)(ep->extra + ep->extra_length), buf, len); | ||
| ep->extra_length += len; | ||
| } else if (alt) { | ||
| tmp = realloc((void *)alt->extra, alt->extra_length + len); | ||
| if (!tmp) { | ||
| perror("realloc"); | ||
| desc_file_free_config_descriptor(cfg); | ||
| return NULL; | ||
| } | ||
| alt->extra = tmp; | ||
| memcpy((void *)(alt->extra + alt->extra_length), buf, len); | ||
| alt->extra_length += len; | ||
| } else if (cfg) { | ||
| tmp = realloc((void *)cfg->extra, cfg->extra_length + len); | ||
| if (!tmp) { | ||
| perror("realloc"); | ||
| desc_file_free_config_descriptor(cfg); | ||
| return NULL; | ||
| } | ||
| cfg->extra = tmp; | ||
| memcpy((void *)(cfg->extra + cfg->extra_length), buf, len); | ||
| cfg->extra_length += len; | ||
| } | ||
| break; | ||
| } |
Check notice
Code scanning / CodeQL
Long switch case
| (struct libusb_endpoint_descriptor *)&alt->endpoint[k]; | ||
| if (!ep) | ||
| continue; | ||
| if (ep->extra) |
Check notice
Code scanning / CodeQL
Guarded Free
| if (ep->extra) | ||
| free((void *)ep->extra); | ||
| } | ||
| if (alt->endpoint) |
Check notice
Code scanning / CodeQL
Guarded Free
| } | ||
| if (alt->endpoint) | ||
| free((void *)alt->endpoint); | ||
| if (alt->extra) |
Check notice
Code scanning / CodeQL
Guarded Free
| if (alt->extra) | ||
| free((void *)alt->extra); | ||
| } | ||
| if (ifc->altsetting) |
Check notice
Code scanning / CodeQL
Guarded Free
| if (ifc->altsetting) | ||
| free((void *)ifc->altsetting); | ||
| } | ||
| if (cfg->interface) |
Check notice
Code scanning / CodeQL
Guarded Free
| } | ||
| if (cfg->interface) | ||
| free((void *)cfg->interface); | ||
| if (cfg->extra) |
Check notice
Code scanning / CodeQL
Guarded Free
All existing callers of get_vendor_product_with_fallback() already have the device descriptor available. By passing it directly, we avoid an unnecessary call to libusb_get_device_descriptor() inside the function. Signed-off-by: Ricardo Ribalda <ribalda@google.com>
Add a new flag that allows dumping a USB descriptor file in a human-readable format. This is particularly useful for analyzing descriptor dumps collected from systems where lsusb cannot be run directly, such as during hardware bring-up or on non-Linux platforms. The descriptor file is typically obtained from: /sys/bus/usb/devices/[device-bus-id]/descriptors The normal workflow will be something like: HOST # scp target:/sys/bus/usb/devices/X-X/descriptors . HOST # lsusb -F descriptors Signed-off-by: Ricardo Ribalda <ribalda@google.com>
|
Hi Greg, did you have to look into this? |